package cpr.context;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cpr.Printer;
import cpr.Rule;
import cpr.data.HLVector;
import cpr.utils.SizeOf;

public class RenumberContext {
	Context ctx = null;
    
	public RenumberContext (Context ctx) {
		this.ctx = ctx;
	}
	public Context getContext() {
		return ctx;
	}
    public void writeToDictionary(Collection keys, Map keyMap) throws IOException {
        writeToDictionary(keys, keyMap, null);
        
    }
	
    public Writer writeToDictionary(Collection keys, Map keyMap, Writer writer) throws IOException {

        boolean ownWriter = false;
        if (writer==null) {
            ownWriter = true;
            Writer dictw = new FileWriter(dictFile,true);
            writer = new BufferedWriter(dictw);
        }

        for (Iterator iter = keys.iterator(); iter.hasNext();) {
                Integer digital = (Integer) iter.next();
                String key = (String)keyMap.get(digital);
                //Printer.println(digital+"->"+key);
                writer.write(""+digital+"\t"+key+"\n");
        }
        if (ownWriter) {
            writer.close();
        }
        return writer;
    }
    
	public int TEST_SCORE = 0;
	public String readFrom = null;
	public String writeTo = null;
	public String dictFile = null;
	public int writeToIndex = -1;
	public int counter = 0;
	
	public void switchToNextFile() {
		switch (writeToIndex) {
		case -1:
			readFrom = ctx.getRawDataFilePath();
			writeTo = ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp1";
			writeToIndex = 2;
			break;
		case 1:
			readFrom = ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp2";;
			writeTo = ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp1";
			writeToIndex = 2;
			break;
		case 2:
			readFrom = ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp1";
			writeTo = ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp2";
			writeToIndex = 1;
			break;
		}
	}
	
	public String getFinalFile() {
		return writeTo;
	}
	public String getUnusedTempFile() {
		if (writeTo.equals(ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp1")) {
			return ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp2";
		} else {
			return ctx.getDigitalDataFilenameFor(ctx.getRawDataFilePath())+".temp1";
		}
	}
       public void copyRulesFromHLFile(String filename, String newfilename, String vectorRule, HLVector vector) {
            try {
                Reader f = new FileReader(filename);
                Writer wr = new FileWriter(newfilename);
                BufferedReader br = new BufferedReader(f);
                String s = null;
                int currentRecord = 1;
                int foundRecord = 0;
                int ruleNr = 0;
                int ruleNrGlobal = 0;
                
                do {
                    s=br.readLine();
                    if (s!=null) {
                        Rule r = getContext().getIOContext().createFromHLString(s,ruleNr,ruleNrGlobal);
                        ruleNr++;
                        ruleNrGlobal++;
                        String si = getContext().getPrintContext().printRuleAccordingToVectorLongOld(r, vector);

                    
                        if (vectorRule.equals(si)) {
                            wr.write(s+"\n");
                            foundRecord++;
                          //  Printer.println(getContext().isVerbose(), "found: "+foundRecord+ "| "+currentRecord);
                        }
                        currentRecord++;
                        if (currentRecord%100000==0) {
                            Printer.println("scanned: "+currentRecord+", found: "+foundRecord);
                        }
                    }
                }while (s!=null);
                f.close();            
                wr.close();     
                Printer.println("ok ("+foundRecord+"/"+currentRecord+")");      
                
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            
        }
     
    
    public int selectDistinct(boolean attribute, HLVector vector) {
         try {
             int []hlis = getContext().getScoreHelper().firstSetScoreOf(vector);
             int hl=hlis[0];
             int hli=hlis[1];
             
             Reader f = new FileReader(getContext().getRenumberContext().readFrom);
             BufferedReader br = new BufferedReader(f);
             Writer w = new FileWriter(getContext().getRenumberContext().writeTo);
             BufferedWriter bw = new BufferedWriter(w);
             
             
             String s = null;
             int cnt = 1;
             //HashMap map = new HashMap();
             Set uset = new HashSet();
             HashMap meaningKeyMap = new HashMap();
             HashMap mapCounter = new HashMap();
             int ruleNr = 0;
             int ruleNrGlobal = 0;
             do {
                 s=br.readLine();
                 if (s!=null) {
                     Rule r = ctx.getIOContext().createFromHLDigitalString(s,false, ruleNr, ruleNrGlobal);
                     ruleNr++;
                     ruleNrGlobal++;
                     
                     //int old_size = map.keySet().size();
                     int old_size = uset.size();
                     
                     //String si = printRuleAccordingToVectorOld(r, vector);
                     String si = getContext().getPrintContext().printRuleAccordingToVectorLongOld(r, vector);
                     if (attribute) {
                         si = si + r.attrValue;
                     } else {
                         int t= 1;
                     }
                     
                     String meaningKey = getContext().getPrintContext().printRuleOnlyMeaningKey(r,vector);
                     if (meaningKey==null) {
                         meaningKey = r.attrValue;
                     } else if ("".equals(meaningKey)) {
                         int tt = 1;
                     }
                     uset.add(si); 
                     //map.put(si, r);
                     
                     if (old_size!=uset.size()) {
//                         reportMem(uset);
                         
                         if (getContext().getRenumberContext().counter%1000 == 0) {
                             System.gc();
                             Printer.println(Printer.currDate() + " dc="+getContext().getRenumberContext().counter+" map size="+uset.size()+" freemem="+Runtime.getRuntime().freeMemory());
                            
                         
                         }
                         
                         mapCounter.put(si, new Integer(getContext().getRenumberContext().counter++));
                         meaningKeyMap.put(si, meaningKey);
                     }
                     

                     int dig_value = ((Integer)mapCounter.get(si)).intValue();
                     if (attribute) {
                         r.setAttrValueDigital(dig_value);
                             
                     } else {
                         r.setHLValueDigital(Rule.HLH[Rule.HLIS[hl]][hli], dig_value);
                         
                     }
                     bw.write(r.toHLDigitalString()+"\n");
                 }
                 cnt++;
                 int RULES_TO_LOAD = getContext().getRulesToLoad();
                 if ((RULES_TO_LOAD>0)&&(cnt>RULES_TO_LOAD)) {
                     s = null;
                 }
             }while (s!=null);
             f.close();  
             bw.close();
             
             Map digToString = new HashMap();
             for (Iterator iter = meaningKeyMap.keySet().iterator(); iter.hasNext();) {
                String si = (String) iter.next();
                String key = (String)meaningKeyMap.get(si);
                Integer digital = (Integer)mapCounter.get(si);
                digToString.put(digital, key);
            }
             List sortedDigs = new ArrayList(digToString.keySet().size());
             sortedDigs.addAll(digToString.keySet());
             Collections.sort(sortedDigs);
             getContext().getRenumberContext().writeToDictionary(sortedDigs, digToString);
             Printer.println("sizeof uset = " + SizeOf.sizeOf(uset));
             Printer.println("sizeof sortedDigs = " + SizeOf.sizeOf(sortedDigs));
             Printer.println("sizeof digToString = " + SizeOf.sizeOf(digToString));
             Printer.println("sizeof meaningKeyMap = " + SizeOf.sizeOf(meaningKeyMap));
             Printer.println("sizeof mapCounter = " + SizeOf.sizeOf(mapCounter));
             return getContext().getRenumberContext().counter;
         } catch (Exception ex) {
             ex.printStackTrace();
         }
         return getContext().getRenumberContext().counter;
    }
    
    
    public void copyDigitalToPureDigital() {
    	 try {
    		 Reader f = new FileReader(getContext().getDigitalDataFilePath());
             BufferedReader br = new BufferedReader(f);
             
             try {
                File df = new File(getContext().getPureDigitalDataFilePath());
                if (df.exists()) {
                    df.delete();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
             
             OutputStream w = new FileOutputStream(getContext().getPureDigitalDataFilePath());
             BufferedOutputStream bw = new BufferedOutputStream(w); 
             
//             Rule.totalRuleNr = 0;
             String s = null;
             int cnt = 1;
             int ruleNr = 0;
             int ruleNrGlobal = 0;
             do {
                 s=br.readLine();
                 if (s!=null) {
                     Rule r = getContext().getIOContext().createFromHLDigitalString(s,false,ruleNr++, ruleNrGlobal++);
                     getContext().getIOContext().writePureDigitalRule(r, bw);
                 }
                 cnt++;
                 int RULES_TO_LOAD = getContext().getRulesToLoad();
                 if ((RULES_TO_LOAD>0)&&(cnt>RULES_TO_LOAD)) {
                     s = null;
                 }
             }while (s!=null);
             f.close();  
             bw.close();
         } catch (Exception ex) {
             ex.printStackTrace();
         }
    }
}
